{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 步骤五：（可选）获取结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "TrustedFlow允许用户对可信APP的执行结果（比如模型、预测结果、处理后的数据等）进行导出，导出结果数据需要获得所有数据提供方的集体同意。TrustedFlow提供了CLI工具帮助用户进行结果导出。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据导出流程原理\n",
    "\n",
    "假设alice希望获得结果数据，这份结果数据是由alice和bob提供的数据加工得到的，那么数据导出的流程如下。\n",
    "\n",
    "![data_output](../images/data_output.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据导出示例\n",
    "\n",
    "我们以前文为例，按照前文的步骤，我们完成了使用TrustedFlow对breast cancer数据集进行可信建模，其中在执行XGBoost训练APP的时候，我们会得到一个加密的XGBoost模型。现在假如alice希望得到模型，则可以按照下列步骤进行。导出过程中需要使用到CLI工具，前文中已经有过介绍。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 定位要导出的文件ID\n",
    "\n",
    "每一份文件都有一个ID与之对应，您可以按照步骤三的说明，找到可信APP——XGBoost训练对应的任务配置文件`xgb.json`，我们会找到输出文件的说明。\n",
    "如下所示，`file://output/?id=model_uuid&&uri=/host/testdata/breast_cancer/xgb_model`说明XGBoost训练APP得到的模型ID叫做`model_uuid`，文件位置为`/host/testdata/breast_cancer/xgb_model`。注意，由于occlum使用`host`指代其运行所在目录，所以最终文件应该存储在occlum_instance目录下的`testdata/breast_cancer/xgb_model`。该文件是加密的，我们假设alice从carol中得到了这个文件。\n",
    "\n",
    "```json\n",
    "{\n",
    "    {\n",
    "        \"output_uris\": [\n",
    "            \"file://output/?id=model_uuid&&uri=/host/testdata/breast_cancer/xgb_model\"\n",
    "            ]\n",
    "    }\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 获取数据密钥\n",
    "\n",
    "#### 2.1 alice发起导出数据投票请求并签名\n",
    "\n",
    "把下列的内容拷贝到一个空文件中，假如您把文件内容保存为文件vote-request.yaml。\n",
    "该文件主要包含两块内容：\n",
    "\n",
    "- `vote_request`：描述了alice请求要下载的数据、alice的证书、私钥等信息。\n",
    "\n",
    "这一步您需要填写以下项目：\n",
    "\n",
    "- `vote_request.type`: 请求类型（下载必须为`TEE_DOWNLOAD`）\n",
    "- `vote_request.approved_threshold`: 需要同意导出的机构数，因为只需要bob同意即可，所以这里填写1。\n",
    "- `vote_request.approved_action`: 表示同意所做的操作。由逗号分割，`tee/download`的含义为数据导出（请勿修改），后者为要导出的数据ID，即上一步得到的数据ID，请替换`xxxx_uuid`为该数据ID。这里如果您要导出其他数据，记得修改为对应的数据ID。\n",
    "- `vote_request.cert_chain_file`: 数据导出请求方（示例是alice）的证书和CA证书（如果有）。\n",
    "- `vote_request.private_key_file`: 数据导出请求方（示例是alice）的私钥。\n",
    "\n",
    "\n",
    "```yaml\n",
    "vote_request:\n",
    "  # (required) str, vote type, should be \"TEE_DOWNLOAD\" when export data keys for tee tasks' encrypted result\n",
    "  type: \"TEE_DOWNLOAD\"\n",
    "  # (required) int, vote approved threshold\n",
    "  approved_threshold: 1\n",
    "  # (required) str, vote approved action, shoule be \"tee/download,xxxx_uuid\", replace \"xxxx_uuid\" with tee task's result data_uuid\n",
    "  approved_action: \"tee/download,xxxx_uuid\"\n",
    "  # (required) List[str], cert chain files, the order is [cert, mid_ca_cert, root_ca_cert]\n",
    "  # file num can be 1 if the cert is self-signed\n",
    "  cert_chain_file: \n",
    "    - \"alice.crt\"\n",
    "  # (required) str, file contains private key\n",
    "  private_key_file: \"alice.key\"\n",
    "```\n",
    "\n",
    "正确填写之后，alice执行下列命令，对自身的投票请求进行签名。\n",
    "\n",
    "```bash\n",
    "cms_util sign-vote-request --vote-request-file vote-request.yaml --signed-vote-request-file signed-vote-request.yaml\n",
    "```\n",
    "\n",
    "执行之后，signed-vote-request.yaml中会包含以下几个字段：\n",
    "- `cert_chain`: 从`cert_chain_file`读取到的证书链内容\n",
    "- `body`: 将整个`vote_request`（不包含私钥和签名部分）json化并base64编码后的结果\n",
    "- `vote_request_signature`: 使用`private_key_file`中的私钥对的`body`签名值\n",
    "\n",
    "```yaml\n",
    "cert_chain:\n",
    "  - \"-----BEGIN CERTIFICATE-----\\nxxxx\\n-----END CERTIFICATE-----\\n\"\n",
    "body: \n",
    "  xxxx\n",
    "vote_request_signature: \n",
    "  xxxx\n",
    "\n",
    "```\n",
    "\n",
    "这里需要关注的是`vote_request_signature`，这个其实是把上面`vote_request`的内容（不包含私钥和签名部分）转换成了json并且进行了base64签名。(如果您有兴趣可以用base64进行解码进行查看)\n",
    "\n",
    "找到`vote_request_signature`之后，把对应的内容给到bob，bob需要对该内容进行签名。\n",
    "\n",
    "\n",
    "#### 2.2 bob对数据导出请求投票并进行签名\n",
    "\n",
    "首先，bob需要把以下内容复制到一个空文件，假设文件叫做voter.yaml。该文件说明如下：\n",
    "\n",
    "- `vote_request_signature`: 上一步alice得到的数据导出请求的内容，拷贝到这里。记住，请替换为您实际得到的内容。\n",
    "- `action`: `APPROVE`表示同意alice的请求，无需修改。\n",
    "- `cert_chain_file`: bob的证书文件。\n",
    "- `private_key_file`: bob自己的私钥，用于签名。\n",
    "\n",
    "```yaml\n",
    "# (required) str, vote request signature\n",
    "vote_request_signature: xxxx\n",
    "# (required) str, APPROVE/REJECT\n",
    "action: \"APPROVE\"\n",
    "# (required) List[str], cert chain files, the order is [cert, mid_ca_cert, root_ca_cert]\n",
    "# file num can be 1 if the cert is self-signed\n",
    "cert_chain_file: \n",
    "  - \"bob.crt\"\n",
    "# (required) str, file contains voter's private key\n",
    "private_key_file: \"bob.key\"\n",
    "```\n",
    "\n",
    "接下来，bob执行以下命令对同意导出的投票进行签名：\n",
    "```bash\n",
    "cms_util voter-sign --voter-file voter.yaml --signed-voter-file signed-voter.yaml\n",
    "```\n",
    "\n",
    "bob得到的signed-voter.yaml中会包含以下几个字段：\n",
    "- `cert_chain`: 从`cert_chain_file`读取到的证书链内容\n",
    "- `body`: 将整个voter.yaml（不包含私钥和签名部分）json化并base64编码后的结果\n",
    "- `voter_signature`: bob使用`private_key_file`中的私钥对的`body`签名值\n",
    "\n",
    "```yaml\n",
    "cert_chain:\n",
    "  - \"-----BEGIN CERTIFICATE-----\\nxxxx\\n-----END CERTIFICATE-----\\n\"\n",
    "body: \n",
    "  xxxx\n",
    "voter_signature: \n",
    "  xxxx\n",
    "\n",
    "```\n",
    "\n",
    "bob将这个签名结果signed-voter.yaml发送给alice\n",
    "\n",
    "#### 2.3 alice获取bob投票的签名结果，生成数据导出请求\n",
    "\n",
    "alice根据自己生成的signed-vote-request.yaml以及bob签名后发送来的signed-voter.yaml，生成完整的投票结果，用于数据导出请求。\n",
    "\n",
    "```bash\n",
    "cms_util generate-vote-result --signed-vote-request-file signed-vote-request.yaml --signed-voter-files signed-voter.yaml --vote-result-file vote-result.json\n",
    "```\n",
    "\n",
    "\n",
    "#### 2.4 alice向CapsuleManager获取数据密钥并解密\n",
    "\n",
    "打开CLI工具的配置文件（即步骤二、三中提到的alice.yaml和bob.yaml），编辑以下内容：\n",
    "\n",
    "- `party_id`: 填写alice的机构ID（在以前的步骤中您应该已经获得）。\n",
    "- `resource_uri`: 需要导出的数据密钥的id，这里就是xgb模型对应的model_uuid，与2.1步骤中alice发起导出数据投票时的data_uuid是同一个id。\n",
    "- `data_export_certificate_file`: 即上一步得到的文件。\n",
    "\n",
    "```yaml\n",
    "get_export_data_key_b64:\n",
    "  party_id: alice_party_id\n",
    "  resource_uri: model_uuid\n",
    "  data_export_certificate_file: vote-result.json\n",
    "```\n",
    "\n",
    "执行命令，向CapsuleManager请求获取数据加密密钥，预期屏幕会输出数据密钥。\n",
    "\n",
    "```bash\n",
    "cms --config-file alice.yaml get-export-data-key-b64\n",
    "```\n",
    "\n",
    "接着使用得到的数据密钥对模型文件进行解密，记得用实际值替换`数据密钥`，解密后的模型文件为`xgb.model`。\n",
    "```bash\n",
    "cms_util decrypt-file --data-key-b64 数据密钥 --source-file xgb_model --dest-file xgb.model\n",
    "```\n",
    "\n",
    "您可以查看该模型文件，它应该与步骤三里面直接使用明文数据训练得到的模型文件是一致的。\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
